/**
 * @file 通用的筛选表单；（SearchForm里边耦合了业务逻辑，所以不能通用）
 * @author wanglei05
 * @date 2021-01-13
 *  暂时支持类型：DatePicker、RangePicker、Select、Input
 *  支持联动，支持获取数据，服务端搜索，分页
 *
 *  @param config 配置数组
 *  @param selectOptions 设置下拉options
 *  @param initialValues 初始化
 *  @param onOk  成功
 *  @param onReset  重置
 *  @param onItemChange
 *  @param onfetchOptions 获取某个formitem数据
 */


import React, {useImperativeHandle, useEffect, forwardRef, useState} from 'react';
import {
    Form,
    Button,
    Input,
    DatePicker,
    Select,
    Row,
    Col,
    Spin,
    Empty
} from 'antd';
import omit from 'omit.js';
import debounce from 'lodash/debounce';

import popUpContainer from '~/utils/common/popupFix';

import './index.less';

const {RangePicker} = DatePicker;

const SearchForm = (props, ref) => {
    const {
        config, selectOptions, onOk, onReset, onItemChange, onfetchOptions,
        formItemLayout = {},
        initialValues,
        noCache,
        loading
    } = props;
    const [form] = Form.useForm();
    const [formConfig, setFormConfig] = useState(config);

    useImperativeHandle(ref, () => ({
        formFields: form,
    }));

    useEffect(() => {
        setFormConfig(config);
    }, [config]);

    // 通过key找到匹配的select，给options赋值
    useEffect(() => {
        const newFormConfig = formConfig.map(item => {
            if (item.key === selectOptions.key) {
                item.optionsConfig.options = selectOptions.options;
                item.optionsConfig.pager = selectOptions.pager;
                item.props.loading = false;
            }

            return item;
        });

        setFormConfig(newFormConfig);
    }, [selectOptions]);

    // 设置formItem 的 loading属性
    const setLoading = (key, bool) => {
        const newFormConfig = formConfig.map(item => {
            if (item.key === key) {
                item.props.loading = bool;
            }

            return item;
        });

        setFormConfig(newFormConfig);
    };

    const getData = item => {
        const {
            key,
            props: {searchKey},
            dependItemKey,
            dependItemValue,
            isGetingMore,
            optionsConfig: {pager, options, isFromsServer = true} = {}
        } = item;

        if (isFromsServer) {
            const newFormConfig = formConfig.map(item => {
                if (item.key === key) {
                    item.optionsConfig.options = [];
                }
                return item;
            });
            setFormConfig(newFormConfig);
        }

        const fieldsValue = form.getFieldsValue() ?? {};

        onfetchOptions
            && onfetchOptions({
                ...item,
                key,
                dependItemKey,
                searchKey, pager, dependItemValue, isGetingMore, options, fieldsValue,
            });
    };

    // 获取焦点时请求数据
    const handleFocus = (e, item) => {
        const {key, optionsConfig: {options}, dependItemKey} = item;

        const dependItemValue = dependItemKey && form.getFieldValue(dependItemKey);
        // // 存在依赖项时，只有依赖项有值才请求数据
        // if (dependItemKey && !dependItemValue) {
        //     return;
        // }

        if (noCache || !options?.length) {
            setLoading(key, true);

            getData({...item, dependItemValue});
        }
    };

    const handleBlur = (e, item) => {
        item.props = {
            ...item.props,
            searchKey: ''
        };
    };

    // 根据输入搜索
    const handleSearch = debounce((searchKey, item) => {
        const {key, dependItemKey} = item;

        // 存在依赖项时，只有依赖项有值才请求数据
        // if (dependItemKey && !form.getFieldValue(dependItemKey)) {
        //     return;
        // }

        const newFormConfig = formConfig.map(item => {
            if (item.key === key) {
                item.props.loading = true;
                item.props.searchKey = searchKey;
                item.isGetingMore = false;
            }

            return item;
        });

        setFormConfig(newFormConfig);
        getData(item);
    }, 500);

    // 分页
    const handleSearchMore = (e, item) => {
        const {key} = item;
        const {props: {searchKey}} = formConfig.filter(item => item.key === key)[0];

        setLoading(key, true);
        item.optionsConfig.pager = {
            ...item.optionsConfig.pager,
            pageNum: ++item.optionsConfig.pager.pageNum
        };

        item.isGetingMore = true;

        getData({...item, searchKey});
    };


    const renderItem = item => {
        const {pageNum = 1, pageSize = 0, count = 0} = item.optionsConfig?.pager || {};
        const hasMore = pageNum * pageSize < count;
        const {type, optionsConfig: {options} = {}} = item;
        const notFoundContent = item.props?.loading ? <Spin style={{width: '100%'}} /> : <Empty />;

        const typeMaps = {
            datePicker: <DatePicker {...item.props} />,
            input: <Input {...item.props} placeholder="请选择" />,
            rangePicker: <RangePicker {...item.props} />,
            select: (
                <Select
                    {...item.props}
                    onFocus={e => handleFocus(e, item)}
                    onBlur={e => handleBlur(e, item)}
                    onSearch={e => handleSearch(e, item)}
                    dropdownRender={menu => (
                        <>
                            {menu}
                            {hasMore && (
                                <div className="hasMoreBox">
                                    <Button
                                        type="link"
                                        onClick={e => handleSearchMore(e, item)}
                                        loading={item.props?.loading}
                                    >
                                        加载更多
                                    </Button>
                                </div>
                            )}
                        </>
                    )}
                    getPopupContainer={popUpContainer}
                    notFoundContent={notFoundContent}
                    placeholder="请选择"
                >
                    {options?.map(option => (
                        <Select.Option
                            key={option.key}
                            {...option}
                        >
                            {option.label}
                        </Select.Option>
                    ))}
                </Select>
            )
        };

        return typeMaps[type];
    };

    const onFinish = debounce(fieldsValue => {
        onOk && onOk(fieldsValue);
    }, 1000);

    const onValuesChange = (item, all) => {
        const operateItem = formConfig.filter(configItem => configItem.key === Object.keys(item)[0]);
        const {controlItems} = operateItem[0];

        // 改变时，重置被依赖的item
        if (controlItems) {
            form.resetFields(controlItems);
        }

        onItemChange && onItemChange(item, all);
    };

    const handleReset = debounce(() => {
        form.resetFields();
        onReset && onReset();
    }, 1000);


    return (
        <Form
            className="fineBi-common-form"
            {...formItemLayout}
            form={form}
            name="register"
            onFinish={onFinish}
            onValuesChange={onValuesChange}
            scrollToFirstError
            initialValues
            labelCol={{span: 5}}
            {...omit(props, ['config', 'onFinish', 'onValuesChange'])}
        >
            <Row gutter={24}>
                {formConfig.map(item => (
                    <Col span={item.span || 8} key={item.key}>
                        <Form.Item
                            // key={item.key}
                            name={item.key}
                            style={{marginBottom: 16}}
                            {...omit(item, ['key', 'type', 'props'])}
                        >
                            {renderItem(item)}
                        </Form.Item>
                    </Col>
                ))}
                <Form.Item style={{textAlign: 'right', flexGrow: 1, padding: '0 12px'}}>
                    {onReset && (
                        <Button onClick={handleReset} loading={loading}>
                            重置
                        </Button>
                    )}
                    &nbsp;
                    &nbsp;
                    {onOk && (
                        <Button type="primary" htmlType="submit" loading={loading}>
                            搜索
                        </Button>
                    )}
                </Form.Item>
            </Row>
        </Form>
    );
};

export default forwardRef(SearchForm);
